package com.rex.saas.controller;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.rex.saas.bean.BaseResponse;
import com.rex.saas.bean.DeviceBasicData;
import com.rex.saas.bean.ResultCode;
import com.rex.saas.constants.ApiConstant;
import com.rex.saas.constants.Constants;
import com.rex.saas.mqtt.MaMqttManager;
import com.rex.saas.mqtt.MqttManager;
import com.rex.saas.utils.MacAddressUtil;
import com.rex.saas.utils.Sm2CryptoUtil;
import com.rex.saas.utils.Sm4CryptoUtil;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/mqtt")
@Slf4j
public class MqttController extends BaseController{

    @Resource
    private MqttManager mqttManager;

    @Resource
    private MaMqttManager maMqttManager;

    @PostMapping("/up")
    @ResponseBody
    public BaseResponse up(@RequestBody JSONObject triggerRequest){
        log.info("MqttController up:{}", triggerRequest);
        String functionCode = triggerRequest.getString("FunctionCode");
        if(StringUtils.isEmpty(functionCode)){
            return BaseResponse.error(ResultCode.PARAM_ERROR.getStatus(),"FunctionCode is empty");
        }
        String macAddress = MacAddressUtil.getMacAddress();
        String topic = "/paas/" + macAddress + "/up";
        if("DevReportEvent".equals(functionCode)
                || "DevReportProperty".equals(functionCode)
                || "DevReportPropertyList".equals(functionCode)
                || "DevWriteResponse".equals(functionCode)
                || "DevWriteResponseList".equals(functionCode)
                || "ReportDevStatus".equals(functionCode)
                || "DevLeaveNotify".equals(functionCode)
                || "ReadDevTelemetryResponse".equals(functionCode)
                || "Ack".equals(functionCode)){
            try {
                JSONObject upRequest = new JSONObject();
                upRequest.put("VendorCode", triggerRequest.getString("VendorCode"));
                upRequest.put("Timestamp", triggerRequest.getString("Timestamp"));
                upRequest.put("Seq", triggerRequest.getString("Seq"));
                upRequest.put("DeviceId", triggerRequest.getString("GatewayId"));
                upRequest.put("FunctionCode", functionCode);
                upRequest.put("Payload", triggerRequest.getJSONObject("Payload"));

//                log.info("MqttController up upRequest:{}", upRequest.toJSONString());
                String upRequestStr = Sm4CryptoUtil.encrypt(upRequest.toJSONString());
                mqttManager.getMqttConnect().pub(topic, upRequestStr);
//                log.info("MqttController up encrypt upRequest:{}", upRequestStr);

                maMqttManager.getMaMqttConnect().pub(topic, upRequest.toJSONString());
            } catch (MqttException e) {
                log.error("MqttController up triggerRequest:{}", triggerRequest, e);
                return BaseResponse.error(ResultCode.SYSTEM_ERROR);
            }
        }

        if("ReportDevList".equals(functionCode)){
            try {
                JSONObject upRequest = new JSONObject();
                upRequest.put("VendorCode", triggerRequest.getString("VendorCode"));
                upRequest.put("Timestamp", triggerRequest.getString("Timestamp"));
                upRequest.put("Seq", triggerRequest.getString("Seq"));
                upRequest.put("DeviceId", triggerRequest.getString("GatewayId"));
                upRequest.put("FunctionCode", functionCode);
                JSONObject payload = new JSONObject();
                payload.put("List", triggerRequest.getJSONArray("List"));
                upRequest.put("Payload", payload);
                log.info("MqttController up ReportDevList upRequest:{}", upRequest.toJSONString());
                String upRequestStr = Sm4CryptoUtil.encrypt(upRequest.toJSONString());
                mqttManager.getMqttConnect().pub(topic, upRequest.toJSONString());
                log.info("MqttController up ReportDevList upRequestStr:{}", upRequestStr);

                maMqttManager.getMaMqttConnect().pub(topic, upRequest.toJSONString());
            } catch (MqttException e) {
                log.error("MqttController up triggerRequest:{}", triggerRequest, e);
                return BaseResponse.error(ResultCode.SYSTEM_ERROR);
            }
        }

        return BaseResponse.ok();
    }

    @PostMapping("/down")
    @ResponseBody
    public BaseResponse down(@RequestBody JSONObject triggerRequest){
        log.info("MqttController down:{}", triggerRequest);
//        try {
            JSONObject ackResponse = new JSONObject();
            BeanUtils.copyProperties(triggerRequest, ackResponse);
            String functionCode = triggerRequest.getString("FunctionCode");
            if (StringUtils.isEmpty(functionCode)){
                return BaseResponse.error(ResultCode.PARAM_ERROR.getStatus(),"FunctionCode is empty");
            }
            String Seq = triggerRequest.getString("Seq");
            if (StringUtils.isEmpty(Seq)){
                return BaseResponse.error(ResultCode.PARAM_ERROR.getStatus(),"Seq is empty");
            }
            String deviceName = triggerRequest.getString("DeviceName");
            if (StringUtils.isEmpty(deviceName)){
                return BaseResponse.error(ResultCode.PARAM_ERROR.getStatus(),"DeviceName is empty");
            }
            String token = rexolarApiClient.getTenantTokenByUser("abc@qq.com", "123456");
            if(StringUtils.isEmpty( token)){
                return BaseResponse.error(ResultCode.PARAM_ERROR.getStatus(),"Token is empty");
            }
            DeviceBasicData device = rexolarApiClient.getDeviceByDeviceName(deviceName, token);
            if (device==null){
                return BaseResponse.error(ResultCode.PARAM_ERROR.getStatus(),"Device is empty");
            }

            String GateWayId = triggerRequest.getString("GateWayId");
            if (StringUtils.isEmpty(GateWayId)){
                return BaseResponse.error(ResultCode.PARAM_ERROR.getStatus(),"GateWayId is empty");
            }
            DeviceBasicData gateway = rexolarApiClient.getDeviceByDeviceName(GateWayId, token);
            if (gateway==null){
                return BaseResponse.error(ResultCode.PARAM_ERROR.getStatus(),"gateway is empty");
            }

            if ("ReadDevTelemetry".equals(triggerRequest.getString("FunctionCode"))){
                Long startTime = triggerRequest.getLong("StartTime");
                Long endTime = triggerRequest.getLong("EndTime");
                if (StringUtils.isEmpty(startTime)){
                    startTime = DateUtil.parse(DateUtil.today(), "yyyy-MM-dd").getTime();
                }
                if (StringUtils.isEmpty(endTime)) {
                    endTime = System.currentTimeMillis();
                }
                if (startTime > endTime){
                    return BaseResponse.error(ResultCode.PARAM_ERROR.getStatus(),"StartTime must less than EndTime");
                }
                if (endTime - startTime > 86400000){
                    return BaseResponse.error(ResultCode.PARAM_ERROR.getStatus(),"Time range must less than 24 hours");
                }
                JSONArray keys = triggerRequest.getJSONArray("Keys");
                String[] keysArray = new String[keys.size()];
                for (int i = 0; i < keys.size(); i++) {
                    keysArray[i] = keys.getString(i);
                }
                JSONObject payLoad = new JSONObject();
                Map<String, Object> timeSeries = rexolarApiClient.getDeviceTimeSeries(device.getCoreId(),
                        token, keysArray, startTime, endTime,
                        100000, false, 300000L, "AVG", false);
                if(CollectionUtils.isEmpty(timeSeries)){
                    log.error("down getDeviceTimeSeries error, deviceName:{}", triggerRequest.getString("DeviceName"));
                    for (String key : timeSeries.keySet()){
                        payLoad.put(key, null);
                    }
                }else {
                    for (String key : timeSeries.keySet()){
                        List<Map> tmp = (List<Map>) timeSeries.get(key);
                        payLoad.put(key, tmp);
                    }
                }
                ackResponse.put("Payload", payLoad);
                ackResponse.put("FunctionCode", "ReadDevTelemetryResponse");
                ackResponse.put("Timestamp", System.currentTimeMillis());
//                maMqttManager.getMaMqttConnect().pub(topic, ackResponse.toJSONString());

            }else if ("DevWriteProperty".equals(triggerRequest.getString("FunctionCode"))){
                JSONObject gwRpcRequest = new JSONObject();
                BeanUtils.copyProperties(triggerRequest, gwRpcRequest);
                gwRpcRequest.put(Constants.Version, "1.0");
                JSONObject payload = triggerRequest.getJSONObject("Payload");
                payload.put("GroupId", "0");
                payload.put("DeviceId", device.getName());
                gwRpcRequest.remove("DeviceName");
                boolean flag = rexolarApiClient.updateDeviceAttributes(gateway.getCoreId(), ApiConstant.SHARED_SCOPE, gwRpcRequest.toJSONString(), token);
                if (!flag){
                    log.error("down DevWriteProperty updateDeviceAttributes error, deviceName:{}", triggerRequest.getString("DeviceName"));
                    return BaseResponse.error(ResultCode.SYSTEM_ERROR);
                }
                return BaseResponse.ok(flag);
            }

//        } catch (MqttException e) {
//            throw new RuntimeException(e);
//        }
        return BaseResponse.ok();
    }
}